package com.yu.yupicture.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yu.yupicture.Untils.ThrowUntil;
import com.yu.yupicture.constans.UserConstans;
import com.yu.yupicture.exception.ErrorCode;
import com.yu.yupicture.exception.biusnessException;
import com.yu.yupicture.mapper.PictureMapper;
import com.yu.yupicture.mapper.SpaceMapper;
import com.yu.yupicture.mapper.SpaceUserMapper;
import com.yu.yupicture.model.domain.dto.space.SpaceAddRequest;
import com.yu.yupicture.model.domain.dto.space.SpaceEditRequest;
import com.yu.yupicture.model.domain.dto.space.SpaceQueryRequest;
import com.yu.yupicture.model.domain.dto.space.SpaceUpdateRequest;
import com.yu.yupicture.model.domain.entry.Picture;
import com.yu.yupicture.model.domain.entry.Space;
import com.yu.yupicture.model.domain.entry.SpaceUser;
import com.yu.yupicture.model.domain.entry.User;
import com.yu.yupicture.model.domain.vo.SpaceVO;
import com.yu.yupicture.model.domain.vo.UserVo;
import com.yu.yupicture.model.enums.SpaceLevelEnum;
import com.yu.yupicture.model.enums.SpaceRoleEnum;
import com.yu.yupicture.model.enums.SpaceTypeEnum;
import com.yu.yupicture.model.enums.UserRoleEnums;
import com.yu.yupicture.service.SpaceService;
import com.yu.yupicture.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author Li Shuokang
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2025-08-03 14:15:13
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
        implements SpaceService {

    private final UserService userService;
    private final PictureMapper pictureMapper;
    private final TransactionTemplate transactionTemplate;
    private final SpaceUserMapper spaceUserMapper;

    /**
     * 分页查询（管理端，）
     *
     * @param SpaceQueryRequest
     * @return
     */
    @Override
    public Page<Space> page(SpaceQueryRequest SpaceQueryRequest) {
        //校验参数
        ThrowUntil.throwIf(SpaceQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取查询条件
        QueryWrapper<Space> queryWrapper = this.getQueryWrapper(SpaceQueryRequest);

        //分页查询
        return this.page(new Page<>(SpaceQueryRequest.getCurrent(), SpaceQueryRequest.getPageSize()), queryWrapper);
    }

    /**
     * 分页查询（用户端）
     *
     * @param SpaceQueryRequest
     * @return
     */
    @Override
    public Page<SpaceVO> pageVo(SpaceQueryRequest SpaceQueryRequest, User loginUser) {
        //校验参数
        ThrowUntil.throwIf(SpaceQueryRequest == null, ErrorCode.PARAMS_ERROR);
        // 获取查询条件
        QueryWrapper<Space> queryWrapper = this.getQueryWrapper(SpaceQueryRequest);

        //校验权限
        ThrowUntil.throwIf(!Objects.equals(SpaceQueryRequest.getUserId(), loginUser.getId()), ErrorCode.NO_AUTH_ERROR);

        //分页查询
        Page<Space> page = this.page(new Page<>(SpaceQueryRequest.getCurrent(), SpaceQueryRequest.getPageSize()), queryWrapper);

        List<Space> spaceList = page.getRecords();
        if (CollUtil.isEmpty(spaceList)) {
            return new Page<>();
        }
        //转vo
        List<SpaceVO> spaceVOList = this.getSpaceListVoBySpace(spaceList);
        Page<SpaceVO> spacePage = new Page<>(page.getTotal(), page.getPages(), page.getSize());
        spacePage.setRecords(spaceVOList);

        //返回结果
        return spacePage;
    }

    /**
     * 将空间列表进行转vo
     *
     * @param SpaceList
     * @return
     */
    @Override
    public List<SpaceVO> getSpaceListVoBySpace(List<Space> SpaceList) {
        if (CollUtil.isEmpty(SpaceList)) {
            return List.of();
        }
        List<SpaceVO> spaceVOList = SpaceList.stream().map(SpaceVO::objToVo).toList();
        //获取用户id
        Set<Long> userIds = SpaceList.stream().map(Space::getUserId).collect(Collectors.toSet());
        Map<Long, UserVo> userVoMap = userIds.stream().map(
                userId -> {
                    User u = userService.getById(userId);
                    if (u == null) {
                        log.error("分页查询-用户端 user not found,userId:{}", userId);
                    }
                    //脱敏
                    return userService.getUserVo(u);
                }
        ).collect(Collectors.toMap(UserVo::getId, userVo -> userVo));

        //填充用户信息
        return spaceVOList.stream()
                .peek(picVo -> picVo.setUser(userVoMap.get(picVo.getUserId()))).toList();
    }

    /**
     * 将单个空间进行转vo
     *
     * @param Space
     * @return
     */
    @Override
    public SpaceVO getSpaceVoBySpace(Space Space) {
        ThrowUntil.throwIf(Space == null, ErrorCode.PARAMS_ERROR);
        SpaceVO spaceVO = SpaceVO.objToVo(Space);
        // 设置用户信息
        User u = userService.getById(Space.getUserId());
        if (u != null) {
            spaceVO.setUser(userService.getUserVo(u));
        } else {
            log.error("将单个空间转vo 用户不存在");
        }
        return spaceVO;
    }

    /**
     * 根据id获取空间vo
     *
     * @param id
     * @return
     */
    @Override
    public SpaceVO getSpaceVoById(Long id) {
        //1:校验参数
        ThrowUntil.throwIf(id == null, ErrorCode.PARAMS_ERROR);
        //2:获取空间信息
        Space space = this.baseMapper.selectById(id);
        //3:判断空间是否存在
        ThrowUntil.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);

        //5:返回空间信息
        return this.getSpaceVoBySpace(space);
    }

    /**
     * 根据id获取空间(管理员)
     *
     * @param id
     * @return
     */
    @Override
    public Space getSpaceById(Long id) {
        //1:校验参数
        ThrowUntil.throwIf(id == null, ErrorCode.PARAMS_ERROR);
        //2:获取空间信息
        Space space = this.baseMapper.selectById(id);
        //3:判断空间是否存在
        ThrowUntil.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR);
        //4:判断用户是否有权限
        //5:返回空间信息
        return space;
    }

    /**
     * 删除空间 -管理员
     *
     * @param id
     * @return
     */
    @Override
    public boolean deleteById(Long id) {
        //1:校验参数
        ThrowUntil.throwIf(id == null, ErrorCode.PARAMS_ERROR);

        //2:删除空间
        int i = this.baseMapper.deleteById(id);
        if (i < 0) {
            throw new biusnessException(ErrorCode.SYSTEM_ERROR, "删除空间失败");
        }
        //删除空间对应的图片
        int delete = pictureMapper.delete(new LambdaQueryWrapper<Picture>().eq(Picture::getSpaceId, id));
        if (delete < 0) {
            log.error("删除空间对应的图片失败,spaceId:{}", id);
        }
        return i > 0;

    }

    /**
     * 权限校验
     *
     * @param space
     * @param loginUser
     */
    @Override
    public void checkSpace(Space space, User loginUser) {
        //ThrowUntil.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        if (space == null) {
            //公共图库
            if (!Objects.equals(loginUser.getUserRole(), UserConstans.ADMIN) && !Objects.equals(space.getUserId(), loginUser.getId())) {
                throw new biusnessException(ErrorCode.NO_AUTH_ERROR);
            }
        } else {
            //私有图库
            if (!Objects.equals(space.getUserId(), loginUser.getId())) {
                throw new biusnessException(ErrorCode.NO_AUTH_ERROR);
            }
        }
    }

    /**
     * 获取查询条件
     *
     * @param spaceQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {
        if (spaceQueryRequest == null) {
            throw new biusnessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
        }

        Long userId = spaceQueryRequest.getUserId();
        String spaceName = spaceQueryRequest.getSpaceName();
        Integer spaceLevel = spaceQueryRequest.getSpaceLevel();
        String sortField = spaceQueryRequest.getSortField();
        String sortOrder = spaceQueryRequest.getSortOrder();
        Integer spaceType = spaceQueryRequest.getSpaceType();


        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        // 只查询未删除的空间
        queryWrapper.eq("isDelete", 0);
        queryWrapper.eq(ObjUtil.isNotNull(userId), "userId", userId);
        queryWrapper.like(ObjUtil.isNotNull(spaceName), "spaceName", spaceName);
        queryWrapper.eq(ObjUtil.isNotNull(spaceLevel), "spaceLevel", spaceLevel);
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), sortOrder.equals("ascend"), sortField);
        queryWrapper.eq(ObjUtil.isNotNull(spaceType), "spaceType", spaceType);

        return queryWrapper;
    }

    /**
     * 更新空间 -管理员
     *
     * @param spaceUpdateRequest
     * @return
     */
    @Override
    public boolean updateSpace(SpaceUpdateRequest spaceUpdateRequest) {
        //校验参数
        ThrowUntil.throwIf(spaceUpdateRequest == null, ErrorCode.PARAMS_ERROR);
        //获取空间信息
        Space OldSpace = this.baseMapper.selectById(spaceUpdateRequest.getId());
        //判断空间是否存在
        ThrowUntil.throwIf(OldSpace == null, ErrorCode.NOT_FOUND_ERROR);
        //更新空间信息
        Space space = new Space();
        BeanUtil.copyProperties(spaceUpdateRequest, space);
        boolean b = this.updateById(space);
        ThrowUntil.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return b;
    }

    /**
     * 用户更新空间
     *
     * @param spaceEditRequest
     * @param loginUser
     */
    @Override
    public boolean userUpdateSpace(SpaceEditRequest spaceEditRequest, User loginUser) {
        ThrowUntil.throwIf(spaceEditRequest == null, ErrorCode.PARAMS_ERROR);
        //获取空间信息
        Space OldSpace = this.baseMapper.selectById(spaceEditRequest.getId());
        ThrowUntil.throwIf(OldSpace == null, ErrorCode.NOT_FOUND_ERROR);

        //校验更新参数
        String spaceName = spaceEditRequest.getSpaceName();
        if (spaceName == null) {
            throw new biusnessException(ErrorCode.PARAMS_ERROR, "空间名称不能为空");
        }

        if (spaceName.length() > 30) {
            throw new biusnessException(ErrorCode.PARAMS_ERROR, "空间名称不能超过30个字符");
        }
        //更新空间信息
        Space space = new Space();
        BeanUtil.copyProperties(spaceEditRequest, space);
        boolean b = this.updateById(space);
        ThrowUntil.throwIf(!b, ErrorCode.OPERATION_ERROR);
        return b;
    }

    /**
     * 新增空间
     *
     * @param spaceAddRequest
     * @return
     */
    Map<Long, Object> lockMap = new ConcurrentHashMap<>();

    @Override
    public Long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        //校验参数
        ThrowUntil.throwIf(spaceAddRequest == null, ErrorCode.PARAMS_ERROR);

        String spaceName = spaceAddRequest.getSpaceName();
        Integer spaceLevel = spaceAddRequest.getSpaceLevel();
        Integer spaceType = spaceAddRequest.getSpaceType();

        SpaceTypeEnum enumByValue1 = SpaceTypeEnum.getEnumByValue(spaceType);
        ThrowUntil.throwIf(enumByValue1 == null, ErrorCode.PARAMS_ERROR, "空间类型错误");
        //默认为私有空间
        if (spaceType == null) {
            spaceType = SpaceTypeEnum.PRIVATE.getValue();
        }
        if (spaceName == null) {
            throw new biusnessException(ErrorCode.PARAMS_ERROR, "空间名称不能为空");
        }
        if (spaceLevel == null) {
            spaceLevel = SpaceLevelEnum.COMMON.getValue();
        }
        //
        if (loginUser.getUserRole().equals(UserRoleEnums.USER.getValue()) && spaceLevel != SpaceLevelEnum.COMMON.getValue()) {
            throw new biusnessException(ErrorCode.NO_AUTH_ERROR, "普通用户不能创建此空间");
        }

        SpaceLevelEnum enumByValue = SpaceLevelEnum.getEnumByValue(spaceLevel);
        ThrowUntil.throwIf(enumByValue == null, ErrorCode.PARAMS_ERROR, "空间等级错误");

        Long userId = loginUser.getId();
        //判断用户是否已经创建空间
        boolean exists = this.lambdaQuery().eq(Space::getSpaceType, spaceType).eq(Space::getUserId, userId).exists();
        if (exists) {
            throw new biusnessException(ErrorCode.OPERATION_ERROR, "用户已经创建空间");
        }
        //创建空间 --一个用户只能创建一个空间
        Object lock = lockMap.computeIfAbsent(userId, key -> new Object());
        try {
            synchronized (lock) {
                //校验用户是否已经创建空间
                exists = this.lambdaQuery().eq(Space::getSpaceType, spaceType).eq(Space::getUserId, userId).exists();
                if (exists) {
                    throw new biusnessException(ErrorCode.OPERATION_ERROR, "用户已经创建空间");
                }
                //开启事务
                Integer finalSpaceLevel = spaceLevel;
                Space space = new Space();
                Integer finalSpaceType = spaceType;
                transactionTemplate.execute(status -> {
                    space.setUserId(userId);
                    space.setSpaceName(spaceName);
                    space.setSpaceLevel(finalSpaceLevel);
                    space.setMaxCount(enumByValue.getMaxCount());
                    space.setMaxSize(enumByValue.getMaxSize());
                    space.setSpaceType(finalSpaceType);
                    boolean save = this.save(space);
                    if (!save) {
                        throw new biusnessException(ErrorCode.OPERATION_ERROR, "创建空间失败");
                    }
                    //如果是团队空间，添加用户空间关系
                    if (finalSpaceType == SpaceTypeEnum.TEAM.getValue()) {
                        SpaceUser spaceUser = new SpaceUser();
                        spaceUser.setSpaceId(space.getId());
                        spaceUser.setUserId(userId);
                        spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                        int save1 = spaceUserMapper.insert(spaceUser);
                        if (save1 < 1) {
                            throw new biusnessException(ErrorCode.OPERATION_ERROR, "创建空间失败");
                        }
                    }
                    return space.getId();
                });
                return space.getId();
            }
        } finally {
            lockMap.remove(userId);
        }
    }


}




